import re
import random

from web.utils.enc import set_md5
from web.utils.bootstrap import BootStrapForm

from web import models
from django import forms
from django.core.exceptions import ValidationError
from django.conf import settings
from django.db.models import Q

from libs.tengxunyun.sms import MySmsSender
from django_redis import get_redis_connection

def mobile_validate(value):
	mobile_re = re.compile(r'^(13[0-9]|15[0123456789]|17[678]|18[0-9]|14[57])[0-9]{8}$')
	if not mobile_re.match(value):
		raise ValidationError('后端说手机号码格式错误')


class RegisterModelForm(BootStrapForm,forms.ModelForm):

	phone = forms.CharField(
		label = '手机号',
		validators=[mobile_validate,]
	)

	password = forms.CharField(
		label='密码' ,
		widget=forms.PasswordInput,
		max_length=8,
		min_length=4,
		error_messages={
			'max_length': '最大长度不能超过8位',
			'min_length': '最小长度不能低于4位',
		}
	)
	confirm_password = forms.CharField(
		label='确认密码',
		widget=forms.PasswordInput,
		max_length=8,
		min_length=4,
	)
	sms_code = forms.CharField(label='验证码')


	class Meta:
		model = models.UserInfo
		#fields = '__all__'
		fields = ['username','email','phone','password']
	'''
	def __init__(self,*args,**kwargs):
		super().__init__(*args,**kwargs)
		for name,field in self.fields.items():
			field.widget.attrs.update({'class':'form-control'})
			field.widget.attrs.update({'placeholder':'请输入'+field.label})
	'''
	#用户名唯一性校验
	def clean_username(self):
		username = self.cleaned_data.get('username','')
		exists = models.UserInfo.objects.filter(username=username).exists()
		if exists:
			# self.add_error('username','该用户名已存在')
			raise ValidationError('该用户名已存在')
		return username

	#邮箱唯一性验证
	def clean_email(self):
		email = self.cleaned_data.get('email','')
		exists = models.UserInfo.objects.filter(email=email).exists()
		if exists:
			# self.add_error('username','该用户名已存在')
			raise ValidationError('该邮箱已被注册')
		return email

	#手机号唯一性验证
	def clean_phone(self):
		phone = self.cleaned_data.get('phone','')
		exists = models.UserInfo.objects.filter(phone=phone).exists()
		if exists:
			# self.add_error('username','该用户名已存在')
			raise ValidationError('该手机号已被注册')
		return phone


	# 对密码进行加密
	def clean_password(self):
		password = self.cleaned_data.get('password','')
		return set_md5(password)
	# self.cleaned_data['password'] = set_md5(password)

	# 两次密码比较
	def clean(self):
		p1 = self.cleaned_data.get('password','')
		p2 = set_md5(self.cleaned_data.get('confirm_password',''))
		if p1.strip() != p2.strip():
			self.add_error('confirm_password','两次密码不一致')
		return self.cleaned_data

	# 验证码校验
	def clean_sms_code(self):
		phone = self.cleaned_data.get('phone','')
		conn = get_redis_connection('sms_code')
		sms_code = self.cleaned_data.get('sms_code')
		redis_code = conn.get(phone)  #redis 里的数据是bytes字节流
		if not redis_code:
			raise ValidationError('验证码已失效')
		redis_code  = redis_code.decode('utf-8')
		if sms_code.strip() != redis_code:
			raise ValidationError('验证码输入有误')

		return redis_code



class SendSmsForm(forms.Form):
	phone = forms.CharField(
		label = '手机号',
		validators = [mobile_validate,]
	)
	#重新 init方法,接收额外参数
	def __init__(self,request,*args,**kwargs):

		super().__init__(*args,**kwargs)
		self.request=request

	def clean_phone(self):
		phone = self.cleaned_data.get('phone')
		print("phone", phone)
		#校验短信模板
		tpl = self.request.GET.get('tpl') # login

		try:
			tpl_id = settings.SMS_TEMPLATE_ID[tpl]
		except:
			raise ValidationError('短信模板错误!!!')

		#手机号唯一性校验
		obj_list = models.UserInfo.objects.filter(phone=phone)

		# 获取短信验证码时,区分一下是注册还是登录
		if tpl == 'register':
			if obj_list.exists():
				raise ValidationError('该手机号已经注册过了')

		elif tpl == 'login':
			if not obj_list.exists():
				raise ValidationError('手机号未注册,请先注册')

		#手机号和tpl的校验都通过了
		#发送短信
		#1 校验该手机号是不是已经发送过短信了,是不是在有效期内
		conn = get_redis_connection('sms_code')
		ret = conn.get(phone) # get不到返回None
		if  ret:
			raise ValidationError('已经发过了大哥,你慢点')
		#1生成验证码
		sms_code = '%06d' % random.randint(1,999999)
		#2 将验证码保存到redis中

		conn.set(phone,sms_code,ex=settings.SMS_CODE_EXPIRE) #

		sms_obj = MySmsSender()
		send_status = sms_obj.send(phone,tpl_id,sms_code)
		print(send_status)
		if send_status != 'Ok':
			raise ValidationError('后台说:短信发送失败')
		return phone

class LoginSmsForm(BootStrapForm,forms.Form):
	phone = forms.CharField(
		label = '手机号',
		validators = [mobile_validate,]
	)
	sms_code = forms.CharField(label='验证码')

	#手机号唯一性校验
	def clean_phone(self):
		phone = self.cleaned_data.get('phone')
		exists = models.UserInfo.objects.filter(phone=phone).exists()
		if  not exists:
			raise ValidationError('手机号不存在,不要乱搞')

		return phone

	# 验证码校验
	def clean_sms_code(self):
		phone = self.cleaned_data.get('phone','')
		conn = get_redis_connection('sms_code')
		sms_code = self.cleaned_data.get('sms_code')
		redis_code = conn.get(phone)  #redis 里的数据是bytes字节流


		if not redis_code:
			raise ValidationError('验证码已失效')
		redis_code  = redis_code.decode('utf-8')
		if sms_code.strip() != redis_code:
			raise ValidationError('验证码输入有误')

		return redis_code

# 手机号或者邮箱登录的form类

class LoginForm(BootStrapForm,forms.Form):

	username = forms.CharField(label='手机号或者邮箱')
	password = forms.CharField(label='密码',widget =forms.PasswordInput,)
	image_code = forms.CharField(label='验证码')

	def __init__(self,request,*args,**kwargs):
		super().__init__(*args,**kwargs)
		self.request = request

	def clean_password(self):

		pwd = self.cleaned_data.get('password')
		return set_md5(pwd)

	#图片验证码的验证
	# 用户输入的和后台保存的要一致
	def clean_image_code(self):
		user_code = self.cleaned_data.get('image_code')
		session_code = self.request.session.get('image_code')
		# 判断session_code是否已经失效
		if not session_code:
			raise ValidationError('验证已过期,请重新获取')

		if user_code.strip().upper() != session_code.upper():
			raise ValidationError('验证码输入有误,请睁开你的眼睛')

		return session_code


	def clean(self):
		pwd = self.cleaned_data.get('password')
		uname = self.cleaned_data.get('username')
		exists = models.UserInfo.objects.filter(Q(phone=uname) |Q(email=uname),password=pwd).exists()
		if not exists:
			self.add_error('username','用户名或者密码有误!')

		return self.cleaned_data














